/**
 * @author 艾尼亚尔
 * @date 2025/8/18
 * @description 请求工具
 */

import type {AxiosRequestConfig} from 'axios';
import type {AxiosTransform} from "./transformAxios.ts";

// 类型辅助
export type Recordable<T = unknown> = Record<string, T>;

// 缓存配置
export interface CacheConfig {
    enable: boolean;
    maxAge: number;
    maxSize: number;
}

// 缓存项
export interface CacheItem<T = unknown> {
    data: T;
    timestamp: number;
}

const toString = Object.prototype.toString;
const DATE_TIME_FORMAT = 'YYYY-MM-DD HH:mm';

/**
 * @description axios 实例创建参数扩展
 */
export interface CreateAxiosOptions extends AxiosRequestConfig {
    authenticationScheme?: string;
    joinTime: boolean;
    transform?: AxiosTransform;
    urlPrefix?: string;
    requestOptions?: Recordable;
    useCache?: boolean;
    maxConcurrent?: number;
    retry?: number;
    retryDelay?: number;
    retryableStatus?: number[];
    maxQueueSize?: number;
    cacheConfig?: Partial<CacheConfig>;
}

/**
 * @description 扩展的请求配置
 */
export interface ExtendedAxiosRequestConfig<T = unknown> extends AxiosRequestConfig {
    priority?: number;           // 请求优先级
    useCache?: boolean;          // 是否使用缓存
    cacheId?: string | number;
    resolve?: (value: T) => void;  // Promise resolve 函数
    reject?: (reason?: unknown) => void; // Promise reject 函数
    retry?: number;
    retryDelay?: number;
    retryableStatus?: number[];
}

/**
 * @description 重试配置
 */
export interface RetryConfig {
    retries: number;        // 最大重试次数
    retryDelay: number;     // 重试延迟时间（毫秒）
    retryableStatus: number[]; // 需要重试的状态码
}

/**
 * @description 统一接口返回结构
 */
export interface Result<T = unknown> {
    code: number;
    status: number;
    message: string;
    data?: T;
}

/**
 * @description 判断是否为函数
 */
/**
 * 判断是否为函数
 */
export const isFunction = <T>(val: unknown): val is T => typeof val === 'function';

/**
 * @description 判断字符串是否为完整 URL
 */
export const isUrl = (url?: string): boolean => {
    if (!url) return false;
    return /^(http|https):\/\//.test(url);
};

/**
 * @description 判断是否为字符串
 */
export const isString = (val: unknown): val is string => toString.call(val) === `[object String]`;

/**
 * @description 判断是否为对象
 */
export const isObject = (val: unknown): val is Record<string, unknown> =>
    val !== null && toString.call(val) === '[object Object]';

/**
 * @description 给请求参数拼接时间戳，防止缓存
 * @param join 是否拼接
 * @param restful 是否为 restful 风格
 * @returns restful=true 返回字符串，restful=false 返回对象
 */
export const joinTimestamp = (join: boolean, restful = false): string | object => {
    if (!join) {
        return restful ? '' : {};
    }
    const now = new Date().getTime();
    if (restful) {
        return `?_t=${now}`;
    }
    return {_t: now};
}

/**
 * @description 递归格式化请求参数中的时间和字符串
 * @param params 请求参数对象
 */
export const formatRequestDate = (params: Recordable) => {
    if (!isObject(params)) return;

    for (const key in params) {
        if (!Object.prototype.hasOwnProperty.call(params, key)) continue;

        const val = params[key];

        // 1. 判断并处理 moment 对象
        if (val && typeof val === 'object' && '_isAMomentObject' in val) {
            // 先断言成 Record<string, any>，再安全调用 format
            const m = val as Record<string, unknown>;
            params[key] = (m.format as (f: string) => string)(DATE_TIME_FORMAT);
            continue;
        }

        // 2. 处理字符串
        if (isString(val)) {
            params[key] = val.trim();
        }

        // 3. 递归处理嵌套对象
        if (isObject(val)) {
            formatRequestDate(val);
        }
    }
};
